package vip.aster.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.aster.common.constant.Constants;
import vip.aster.common.constant.enums.StatusEnum;
import vip.aster.common.constant.enums.SuperAdminEnum;
import vip.aster.common.excel.ExcelFinishCallBack;
import vip.aster.common.exception.BusinessException;
import vip.aster.common.utils.ExcelUtils;
import vip.aster.common.utils.PageInfo;
import vip.aster.framework.i18n.MessageUtils;
import vip.aster.framework.mybatis.enums.DataScopeEnum;
import vip.aster.framework.security.entity.UserDetail;
import vip.aster.system.entity.SysTenant;
import vip.aster.system.entity.SysUser;
import vip.aster.system.mapper.SysUserMapper;
import vip.aster.system.query.SysUserQuery;
import vip.aster.system.query.SysUserRoleQuery;
import vip.aster.system.service.*;
import vip.aster.system.vo.SysUserExcelVO;
import vip.aster.system.vo.SysUserVO;
import vip.aster.tenant.constants.TenantConstants;
import vip.aster.tenant.utils.TenantUtils;

import java.util.*;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author Aster
 * @since 2023-11-28 10:36
 */
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    private SysUserMapper sysUserMapper;
    private SysRoleService sysRoleService;
    private SysOrgService sysOrgService;
    private SysRoleOrgService sysRoleOrgService;
    private SysMenuService sysMenuService;
    private SysUserRoleService sysUserRoleService;
    private SysUserPostService sysUserPostService;
    private SysTenantService sysTenantService;
    private PasswordEncoder passwordEncoder;

    @Override
    public SysUserVO getUserByMobile(String mobile) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getMobile, mobile);
        SysUser sysUser = this.getOne(queryWrapper);
        if (sysUser == null) {
            return null;
        }
        return new SysUserVO(sysUser);
    }

    @Override
    public UserDetails getUserDetails(SysUserVO user) {
        UserDetail userDetail = SysUserVO.convertDetail(user);

        // 账号不可用
        if (StatusEnum.DISABLE.getCode().equals(userDetail.getStatus())) {
            userDetail.setEnabled(false);
        }

        // 数据权限范围
        List<String> dataScopeList = getDataScope(userDetail);
        userDetail.setDataScopeList(dataScopeList);

        // 用户权限列表
        Set<String> authoritySet = sysMenuService.getUserAuthority(userDetail);
        userDetail.setAuthoritySet(authoritySet);

        // 用户角色
        Set<String> roleCodeSet = sysRoleService.getRoleCode(userDetail);
        userDetail.setRoleCodeSet(roleCodeSet);

        return userDetail;
    }

    @Override
    public SysUserVO getUserByUsername(String username) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = this.getOne(queryWrapper);
        if (sysUser == null) {
            return null;
        }
        return new SysUserVO(sysUser);
    }

    @Override
    public PageInfo<SysUserVO> roleUserPage(SysUserRoleQuery query) {
        IPage<SysUser> page = new Page<>(query.getPageNum(), query.getPageSize());
        Map<String, Object> params = new HashMap<>();
        params.put("roleId", query.getRoleId());
        params.put("username", query.getUsername());
        params.put("mobile", query.getMobile());
        params.put("gender", query.getGender());
        params.put(Constants.PAGE_PARAM, page);
        List<SysUser> userList = sysUserMapper.getRoleUserList(params);
        return new PageInfo<>(SysUserVO.convertList(userList), page.getTotal());
    }

    @Override
    public PageInfo<SysUserVO> pageList(SysUserQuery query) {
        IPage<SysUser> page = new Page<>(query.getPageNum(), query.getPageSize());
        IPage<SysUser> pageList = this.page(page, getWrapper(query));
        return new PageInfo<>(SysUserVO.convertList(pageList.getRecords()), pageList.getTotal());
    }

    @Override
    public void updatePassword(String userId, String newPassword) {
        // 修改密码
        SysUser user = this.getById(userId);
        user.setPassword(newPassword);

        this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysUserVO sysUserVO) {
        SysUser user = new SysUser();
        BeanUtil.copyProperties(sysUserVO, user, true);

        if (StrUtil.isBlank(user.getId())) {
            // 判断用户名是否存在
            SysUserVO userVO = this.getUserByUsername(user.getUsername());
            if (userVO != null) {
                throw new BusinessException(MessageUtils.message("user.save.username.exists"));
            }
            // 判断手机号是否存在
            userVO = this.getUserByMobile(user.getMobile());
            if (userVO != null) {
                throw new BusinessException(MessageUtils.message("user.save.mobile.exists"));
            }
            // 判断租户下用户数量是否超过限制
            boolean isLimit = checkTenantLimit();
            if (isLimit) {
                throw new BusinessException(MessageUtils.message("user.save.tenant.limit"));
            }
            user.setSuperAdmin(SuperAdminEnum.NO.getCode());
            // 设置默认密码
            user.setPassword(passwordEncoder.encode(Constants.DEFAULT_PASSWORD));
            // 保存用户
            sysUserMapper.insert(user);

        } else {
            // 判断用户名是否存在
            SysUserVO userVO = this.getUserByUsername(user.getUsername());
            if (userVO != null && !user.getId().equals(userVO.getId())) {
                throw new BusinessException(MessageUtils.message("user.save.username.exists"));
            }
            // 判断手机号是否存在
            userVO = this.getUserByMobile(user.getMobile());
            if (userVO != null && !user.getId().equals(userVO.getId())) {
                throw new BusinessException(MessageUtils.message("user.save.mobile.exists"));
            }
            sysUserMapper.updateById(user);
        }

        // 保存用户角色关系
        sysUserRoleService.saveRoleList(user.getId(), sysUserVO.getRoleIdList());

        // 更新用户岗位关系
        sysUserPostService.savePostList(user.getId(), sysUserVO.getPostIdList());
    }

    /**
     * 校验注册用户数是否超过限制
     * @return true-超过, false-没有超过
     */
    private boolean checkTenantLimit() {
        if (TenantUtils.isEnable()) {
            String tenantId = TenantUtils.getTenantId();
            if (StrUtil.isBlank(tenantId)) {
                return false;
            }
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysUser::getTenantId, tenantId);
            // 已存在用户数量
            long userCount = this.count(queryWrapper);
            SysTenant tenant = sysTenantService.getById(tenantId);
            int accountCount = tenant.getAccountCount();
            return accountCount != TenantConstants.USER_LIMIT_NUM && userCount >= accountCount;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<String> idList) {
        this.removeBatchByIds(idList);

        // 删除用户角色关系
        sysUserRoleService.deleteByUserIdList(idList);

        // 删除用户岗位关系
        sysUserPostService.deleteByUserIdList(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importByExcel(MultipartFile file, String password) {
        ExcelUtils.readAnalysis(file, SysUserExcelVO.class, new ExcelFinishCallBack<SysUserExcelVO>() {
            @Override
            public void doAfterAllAnalysed(List<SysUserExcelVO> result) {
                saveUser(result);
            }

            @Override
            public void doSaveBatch(List<SysUserExcelVO> result) {
                saveUser(result);
            }

            private void saveUser(List<SysUserExcelVO> result) {
                List<SysUser> sysUserEntities = BeanUtil.copyToList(result, SysUser.class);
                sysUserEntities.forEach(user -> user.setPassword(password));
                saveBatch(sysUserEntities);
            }
        });
    }

    @Override
    public void export() {
        List<SysUser> list = this.list(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getSuperAdmin, SuperAdminEnum.NO.getCode()));
        List<SysUserExcelVO> userExcels = SysUserExcelVO.convertList(list);

        // 写到浏览器打开
        String excelName = "user_" + LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DatePattern.NORM_DATE_PATTERN);
        String sheetName = MessageUtils.message("user.export.sheetName");
        ExcelUtils.excelExport(SysUserExcelVO.class, excelName, sheetName, userExcels);

    }

    @Override
    public void editInfo(SysUserVO user) {
        SysUser sysUser = new SysUser();
        sysUser.setId(user.getId());
        sysUser.setAvatar(user.getAvatar());
        sysUser.setNickName(user.getNickName());
        sysUser.setBirthday(user.getBirthday());
        sysUser.setGender(user.getGender());
        sysUser.setSignature(user.getSignature());
        sysUserMapper.updateById(sysUser);
    }

    @Override
    public SysUserVO getUserByTenant(String tenantId, String username) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, tenantId);
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        return sysUser != null ? new SysUserVO(sysUser) : null;
    }

    private LambdaQueryWrapper<SysUser> getWrapper(SysUserQuery query) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StrUtil.isNotBlank(query.getOrgId()), SysUser::getOrgId, query.getOrgId());
        queryWrapper.eq(StrUtil.isNotBlank(query.getStatus()), SysUser::getStatus, query.getStatus());
        queryWrapper.eq(StrUtil.isNotBlank(query.getGender()), SysUser::getGender, query.getGender());
        queryWrapper.like(StrUtil.isNotBlank(query.getUsername()), SysUser::getUsername, query.getUsername());
        if (StrUtil.isNotBlank(query.getName())) {
            queryWrapper.and(q -> q.eq(SysUser::getUsername, query.getName())
                    .or().eq(SysUser::getNickName, query.getName())
                    .or().eq(SysUser::getMobile, query.getName()));
        }
        return queryWrapper;
    }

    private List<String> getDataScope(UserDetail userDetail) {
        String dataScope = sysRoleService.getDataScopeByUserId(userDetail.getId());
        if (StrUtil.isBlank(dataScope)) {
            return new ArrayList<>();
        }

        if (DataScopeEnum.ALL.getValue().equals(dataScope)) {
            // 全部数据权限，则返回null
            return null;
        } else if (DataScopeEnum.ORG_AND_CHILD.getValue().equals(dataScope)) {
            // 本机构及子机构数据
            List<String> dataScopeList = sysOrgService.getSubOrgIdList(userDetail.getOrgId());
            // 自定义数据权限范围
            dataScopeList.addAll(sysRoleOrgService.getDataScopeList(userDetail.getId()));

            return dataScopeList;
        } else if (DataScopeEnum.ORG_ONLY.getValue().equals(dataScope)) {
            // 本机构数据
            List<String> dataScopeList = new ArrayList<>();
            dataScopeList.add(userDetail.getOrgId());
            // 自定义数据权限范围
            dataScopeList.addAll(sysRoleOrgService.getDataScopeList(userDetail.getId()));

            return dataScopeList;
        } else if (DataScopeEnum.CUSTOM.getValue().equals(dataScope)) {
            // 自定义数据权限范围
            return sysRoleOrgService.getDataScopeList(userDetail.getId());
        }

        return new ArrayList<>();
    }
}
